package com.yuye.java.redis.redisson;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.yuye.java.redis.properties.RedisProperties;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.ReadMode;
import org.redisson.config.SentinelServersConfig;
import org.redisson.config.SingleServerConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * Redisson配置类
 * @author gzs
 * @version 3.0.0
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class RedissonConfig {
	
	@Autowired
    RedisProperties redisProperties;
	@Configuration
    @ConditionalOnClass({Redisson.class})
    @ConditionalOnExpression("'${spring.redis.mode}'=='single' or '${spring.redis.mode}'=='cluster' or '${spring.redis.mode}'=='sentinel'")
    protected class RedissonSingleClientConfiguration {

	    public static final int MAX_CONNECT = 16;

        /**
         * 单机模式 redisson 客户端
         */
        @Bean
        @ConditionalOnProperty(name = "spring.redis.mode", havingValue = "single")
        RedissonClient redissonSingle() {
            Config config = new Config();
            String node = redisProperties.getHost() + ":" + redisProperties.getPort();
            node = node.startsWith("redis://") ? node : "redis://" + node;
            SingleServerConfig serverConfig = config.useSingleServer()
                    .setAddress(node)
                    .setTimeout(redisProperties.getPool().getConnTimeout())
                    .setConnectionPoolSize(redisProperties.getPool().getSize())
                    .setConnectionMinimumIdleSize(redisProperties.getPool().getMinIdle());
            if (StringUtils.isNotBlank(redisProperties.getPassword())) {
                serverConfig.setPassword(redisProperties.getPassword());
            }
            commonHandleForRedis(config);
            return Redisson.create(config);
        }


        /**
         * 集群模式的 redisson 客户端
         *
         * @return
         */
        @Bean
        @ConditionalOnProperty(name = "spring.redis.mode", havingValue = "cluster")
        RedissonClient redissonCluster() {
            System.out.println("cluster redisProperties:" + redisProperties.getCluster());

            Config config = new Config();
            String[] nodes = redisProperties.getCluster().getNodes().split(",");
            List<String> newNodes = new ArrayList(nodes.length);
            Arrays.stream(nodes).forEach((index) -> newNodes.add(
                    index.startsWith("redis://") ? index : "redis://" + index));

            ClusterServersConfig serverConfig = config.useClusterServers()
                    .addNodeAddress(newNodes.toArray(new String[0]))
                    .setScanInterval(
                            redisProperties.getCluster().getScanInterval())
                    .setIdleConnectionTimeout(
                            redisProperties.getPool().getSoTimeout())
                    .setConnectTimeout(
                            redisProperties.getPool().getConnTimeout())
                    .setFailedSlaveReconnectionInterval(
                            redisProperties.getCluster().getFailedAttempts())
                    .setRetryAttempts(
                            redisProperties.getCluster().getRetryAttempts())
                    .setRetryInterval(
                            redisProperties.getCluster().getRetryInterval())
                    .setMasterConnectionPoolSize(redisProperties.getCluster()
                            .getMasterConnectionPoolSize())
                    .setSlaveConnectionPoolSize(redisProperties.getCluster()
                            .getSlaveConnectionPoolSize())
                    .setTimeout(redisProperties.getTimeout());
            if (StringUtils.isNotBlank(redisProperties.getPassword())) {
                serverConfig.setPassword(redisProperties.getPassword());
            }
            commonHandleForRedis(config);
            return Redisson.create(config);
        }

       /**  
         * 哨兵模式 redisson 客户端
         * @return
         */

        @Bean
        @ConditionalOnProperty(name = "spring.redis.mode", havingValue = "sentinel")
        RedissonClient redissonSentinel() {
            log.info("sentinel redisProperties:" + redisProperties.getSentinel());
            Config config = new Config();
            String[] nodes = redisProperties.getSentinel().getNodes().split(",");
            List<String> newNodes = new ArrayList(nodes.length);
            Arrays.stream(nodes).forEach((index) -> newNodes.add(
                    index.startsWith("redis://") ? index : "redis://" + index));

            SentinelServersConfig serverConfig = config.useSentinelServers()
                    .addSentinelAddress(newNodes.toArray(new String[0]))
                    .setMasterName(redisProperties.getSentinel().getMaster())
                    .setReadMode(ReadMode.SLAVE)
                    .setFailedSlaveReconnectionInterval(redisProperties.getSentinel().getFailMax())
                    .setTimeout(redisProperties.getTimeout())
                    .setMasterConnectionPoolSize(redisProperties.getPool().getSize())
                    .setSlaveConnectionPoolSize(redisProperties.getPool().getSize())
                    .setSlaveConnectionMinimumIdleSize(MAX_CONNECT)
                    ;

            if (StringUtils.isNotBlank(redisProperties.getPassword())) {
                serverConfig.setPassword(redisProperties.getPassword());
            }
            commonHandleForRedis(config);
            return Redisson.create(config);
        }
    }
	
	private void commonHandleForRedis(Config config) {
		config.setCodec(new StringCodec());
	}
	
	
	
	@Bean
	public JedisPoolConfig jedisPoolConfig() {
	    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
	    jedisPoolConfig.setMaxTotal(redisProperties.getPool().getMaxActive());
	    jedisPoolConfig.setMaxIdle(redisProperties.getPool().getMaxIdle());
	    jedisPoolConfig.setMinIdle(redisProperties.getPool().getMinIdle());
	    jedisPoolConfig.setMaxWaitMillis(redisProperties.getPool().getConnTimeout());

	    return jedisPoolConfig;
	}

	@Bean
	public JedisPool jedisPool(JedisPoolConfig jedisPoolConfig) {

	    log.info("=====创建JedisPool连接池=====");
	    String host = redisProperties.getHost();
	    Integer port = Integer.parseInt(redisProperties.getPort());
	    int timeout = redisProperties.getPool().getConnTimeout();
	    String password = redisProperties.getPassword();
	    if(StringUtils.isNotEmpty(password)) {
	        return new JedisPool(jedisPoolConfig, host, port, timeout, password);
	    }

	    return new JedisPool(jedisPoolConfig, host, port, timeout);
	}

}
